#define COBJMACROS

#include <Winerror.h>
#include <windows.h>
#include <dxgi.h>
#include <d3d11.h>
#include <dxgi1_2.h>
#include <d3dcompiler.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3dcompiler.lib")

static D3D_DRIVER_TYPE DriverTypes[] = {
    D3D_DRIVER_TYPE_HARDWARE,
    D3D_DRIVER_TYPE_WARP,
    D3D_DRIVER_TYPE_REFERENCE,
};

static UINT NumDriverTypes = ARRAYSIZE(DriverTypes);

static D3D_FEATURE_LEVEL FeatureLevels[] = {
    D3D_FEATURE_LEVEL_12_1,
    D3D_FEATURE_LEVEL_12_0,
    D3D_FEATURE_LEVEL_11_1,
    D3D_FEATURE_LEVEL_11_0,
};

static UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);

typedef struct
{
    ID3D11Device *device;
    ID3D11DeviceContext *context;
    IDXGIOutputDuplication *duplication;
    ID3D11ComputeShader *shader;
    bool rgb;
} DirectX11Session;

static const char shader_code[] =
    "Texture2D<float4> InputTexture : register(t0);\n"
    "RWTexture2D<float4> OutputTexture : register(u0);\n"
    "[numthreads(8, 8, 1)]\n"
    "void CSMain(uint3 id : SV_DispatchThreadID) {\n"
    "    float4 color = InputTexture[id.xy];\n"
    "    OutputTexture[id.xy] = color.bgra;\n"
    "}\n";

HRESULT NewDirectX11Session(DirectX11Session *session, UINT display, bool rgb);
void CloseDirectX11Session(DirectX11Session *session);
HRESULT Screenshot(DirectX11Session *session, INT x, INT y, UINT *width, UINT *height, BYTE **ppBits);
HRESULT CompileShader(DirectX11Session *session);
HRESULT CountAdapters(UINT *count);
HRESULT EnumOutputs(UINT adapter_index, UINT index, INT *left, INT *right, INT *top, INT *bottom, WCHAR *device_name, UINT name_size);